package com.ruoyi.web.controller.campus;

import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.campus.domain.PatrolPoint;
import com.ruoyi.campus.domain.SecurityGuard;
import com.ruoyi.campus.service.IPatrolPointService;
import com.ruoyi.campus.service.ISecurityGuardService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.DateUtil;

/**
 * 巡查点位信息Controller
 * 
 * @author ruoyi
 * @date 2025-06-29
 */
@Api(tags = "巡查点位信息管理")
@RestController
@RequestMapping("/campus/point")
public class PatrolPointController extends BaseController
{

    @Autowired
    private IPatrolPointService patrolPointService;
    
    @Autowired
    private ISecurityGuardService securityGuardService;



    /**
     * 查询巡查点位信息列表
     */
    @ApiOperation("查询巡查点位信息列表")
    @RequiresPermissions("campus:point:list")
    @GetMapping("/list")
    public TableDataInfo list(PatrolPoint patrolPoint)
    {
        startPage();
        List<PatrolPoint> list = patrolPointService.selectPatrolPointList(patrolPoint);
        return getDataTable(list);
    }

    /**
     * 导出巡查点位信息列表
     */
    @ApiOperation("导出巡查点位信息列表")
    @RequiresPermissions("campus:point:export")
    @Log(title = "巡查点位信息", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public AjaxResult export(@RequestBody PatrolPoint patrolPoint)
    {
        List<PatrolPoint> list = patrolPointService.selectPatrolPointList(patrolPoint);
        ExcelUtil<PatrolPoint> util = new ExcelUtil<PatrolPoint>(PatrolPoint.class);
        return util.exportExcel(list, "巡查点位信息数据");
    }



    /**
     * 新增保存巡查点位信息
     */
    @ApiOperation("新增保存巡查点位信息")
    @RequiresPermissions("campus:point:add")
    @Log(title = "巡查点位信息", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult addSave(@RequestBody PatrolPoint patrolPoint)
    {
        return toAjax(patrolPointService.insertPatrolPoint(patrolPoint, getLoginName()));
    }

    /**
     * 修改巡查点位信息
     */
    @ApiOperation("查询巡查点位信息")
    @RequiresPermissions("campus:point:get")
    @GetMapping("/{pointId}")
    public AjaxResult getById(@PathVariable("pointId") Long pointId)
    {
        return AjaxResult.success(patrolPointService.selectPatrolPointByPointId(pointId));
    }

    /**
     * 根据点位唯一编码查询巡查点位信息
     */
    @ApiOperation("根据点位唯一编码查询巡查点位信息")
    @Anonymous
    @GetMapping("/unique/{pointUniqueCode}")
    public AjaxResult getByUniqueCode(@PathVariable("pointUniqueCode") String pointUniqueCode)
    {
        return AjaxResult.success(patrolPointService.selectPatrolPointByUniqueCode(pointUniqueCode));
    }

    /**
     * 修改保存巡查点位信息
     */
    @ApiOperation("修改保存巡查点位信息")
    @RequiresPermissions("campus:point:edit")
    @Log(title = "巡查点位信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult editSave(@RequestBody PatrolPoint patrolPoint)
    {
        // 校验点位ID不能为空
        if (patrolPoint.getPointId() == null)
        {
            return AjaxResult.error("巡查点位ID不能为空");
        }
        
        // 校验点位是否存在
        PatrolPoint existingPoint = patrolPointService.selectPatrolPointByPointId(patrolPoint.getPointId());
        if (existingPoint == null)
        {
            return AjaxResult.error("巡查点位不存在");
        }
        
        return toAjax(patrolPointService.updatePatrolPoint(patrolPoint, getLoginName()));
    }

    /**
     * 绑定安全员到巡查点位
     */
    @ApiOperation("绑定安全员到巡查点位")
    @RequiresPermissions("campus:point:bind")
    @Log(title = "巡查点位绑定安全员", businessType = BusinessType.UPDATE)
    @PostMapping("/bind/{pointId}/{guardId}")
    public AjaxResult bindGuard(@PathVariable("pointId") Long pointId, @PathVariable("guardId") Long guardId)
    {
        // 校验参数
        if (pointId == null || guardId == null)
        {
            return AjaxResult.error("点位ID和安全员ID不能为空");
        }
        
        // 校验点位是否存在
        PatrolPoint existingPoint = patrolPointService.selectPatrolPointByPointId(pointId);
        if (existingPoint == null)
        {
            return AjaxResult.error("巡查点位不存在");
        }
        
        // 校验安全员是否存在
        SecurityGuard existingGuard = securityGuardService.selectSecurityGuardByGuardId(guardId);
        if (existingGuard == null)
        {
            return AjaxResult.error("安全员不存在");
        }
        
        // 更新点位绑定信息
        PatrolPoint patrolPoint = new PatrolPoint();
        patrolPoint.setPointId(pointId);
        patrolPoint.setGuardId(guardId);
        patrolPoint.setBindTime(new Date());
        
        return toAjax(patrolPointService.updatePatrolPoint(patrolPoint, getLoginName()));
    }

    /**
     * 解绑巡查点位的安全员
     */
    @ApiOperation("解绑巡查点位的安全员")
    @RequiresPermissions("campus:point:unbind")
    @Log(title = "巡查点位解绑安全员", businessType = BusinessType.UPDATE)
    @PostMapping("/unbind/{pointId}")
    public AjaxResult unbindGuard(@PathVariable("pointId") Long pointId)
    {
        // 校验参数
        if (pointId == null)
        {
            return AjaxResult.error("点位ID不能为空");
        }
        
        // 校验点位是否存在
        PatrolPoint existingPoint = patrolPointService.selectPatrolPointByPointId(pointId);
        if (existingPoint == null)
        {
            return AjaxResult.error("巡查点位不存在");
        }
        
        // 检查是否已绑定安全员
        if (existingPoint.getGuardId() == null)
        {
            return AjaxResult.error("该点位未绑定安全员，无需解绑");
        }
        
        // 解绑安全员 - 使用专门的解绑方法
        int result = patrolPointService.unbindGuardFromPoint(pointId, getLoginName());
        if (result > 0)
        {
            return AjaxResult.success("解绑成功");
        }
        else
        {
            return AjaxResult.error("解绑失败");
        }
    }

    /**
     * 删除巡查点位信息
     */
    @ApiOperation("删除巡查点位信息")
    @RequiresPermissions("campus:point:remove")
    @Log(title = "巡查点位信息", businessType = BusinessType.DELETE)
    @DeleteMapping( "/{ids}")
    public AjaxResult remove(@PathVariable String ids)
    {
        // 校验ids不能为空
        if (ids == null || ids.trim().isEmpty())
        {
            return AjaxResult.error("删除的巡查点位ID不能为空");
        }
        
        // 校验分割后的ID数组不能为空
        String[] idArray = ids.split(",");
        if (idArray.length == 0)
        {
            return AjaxResult.error("删除的巡查点位ID不能为空");
        }
        
        // 校验每个ID不能为空
        for (String id : idArray)
        {
            if (id == null || id.trim().isEmpty())
            {
                return AjaxResult.error("巡查点位ID格式不正确，不能包含空值");
            }
        }
        
        return toAjax(patrolPointService.deletePatrolPointByPointIds(ids));
    }
    
    /**
     * 获取巡查点位二维码
     * 
     * @param pointId 点位ID
     * @param request 请求对象
     * @param response 响应对象
     */
    @ApiOperation("获取巡查点位二维码")
    @GetMapping("/qrcode/{pointId}")
    public void getQrCode(@PathVariable Long pointId, HttpServletRequest request, HttpServletResponse response)
    {
        try
        {
            // 从数据库获取点位信息
            PatrolPoint patrolPoint = patrolPointService.selectPatrolPointByPointId(pointId);
            if (patrolPoint == null)
            {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.getWriter().write("点位不存在");
                return;
            }
            
            // 检查二维码Base64数据是否存在
            String qrCodeBase64 = patrolPoint.getQrCodeBase64();
            if (StringUtils.isEmpty(qrCodeBase64))
            {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.getWriter().write("二维码数据不存在");
                return;
            }
            
            // 解码Base64数据
            byte[] qrCodeBytes = Base64.getDecoder().decode(qrCodeBase64);
            
            // 设置响应头
            response.setContentType(MediaType.IMAGE_PNG_VALUE);
            response.setHeader("Cache-Control", "max-age=3600"); // 缓存1小时
            response.setContentLength(qrCodeBytes.length);
            
            // 输出二维码数据
            response.getOutputStream().write(qrCodeBytes);
            response.getOutputStream().flush();
        }
        catch (Exception e)
        {
            logger.error("获取二维码失败，点位ID: {}", pointId, e);
            try
            {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().write("获取二维码失败");
            }
            catch (Exception ex)
            {
                logger.error("响应错误信息失败", ex);
            }
        }
    }
    
    /**
      * 解析巡查点位Excel文件
      * 数据从第三行开始，字段分别是：部门名称（必填）、点位名称、楼栋（必填）、楼层、房间号（必填）、点位详细名称、用途、点位编码（必填）
      */
     private List<PatrolPoint> parsePatrolPointExcel(InputStream inputStream) throws Exception
     {
         List<PatrolPoint> patrolPointList = new ArrayList<>();
         Workbook workbook = null;
         
         try {
             // 尝试创建工作簿
             try {
                 workbook = new XSSFWorkbook(inputStream);
             } catch (Exception e) {
                 inputStream.reset();
                 workbook = new HSSFWorkbook(inputStream);
             }
             
             Sheet sheet = workbook.getSheetAt(0);
             
             // 从第三行开始读取数据（索引为2）
             for (int i = 2; i <= sheet.getLastRowNum(); i++) {
                 Row row = sheet.getRow(i);
                 if (row == null) {
                     continue;
                 }
                 
                 // 检查是否为空行
                 boolean isEmptyRow = true;
                 for (int j = 0; j < 9; j++) {
                     Cell cell = row.getCell(j);
                     if (cell != null && StringUtils.isNotEmpty(getCellStringValue(cell))) {
                         isEmptyRow = false;
                         break;
                     }
                 }
                 
                 if (isEmptyRow) {
                     continue;
                 }
                 
                 PatrolPoint patrolPoint = new PatrolPoint();
                 
                 // 第1列：部门名称（必填）
                 Cell deptNameCell = row.getCell(0);
                 if (deptNameCell != null) {
                     patrolPoint.setDeptName(getCellStringValue(deptNameCell));
                 }
                 
                 // 楼栋（必填）
                 Cell buildingCell = row.getCell(1);
                 if (buildingCell != null) {
                     patrolPoint.setBuilding(getCellStringValue(buildingCell));
                 }
                 
                 // 楼层
                 Cell floorCell = row.getCell(2);
                 if (floorCell != null) {
                     patrolPoint.setFloor(getCellStringValue(floorCell));
                 }
                 
                 // 房间号（必填）
                 Cell roomNumberCell = row.getCell(3);
                 if (roomNumberCell != null) {
                     patrolPoint.setRoomNumber(getCellStringValue(roomNumberCell));
                 }
                 
                 // 点位详细名称
                 Cell detailNameCell = row.getCell(4);
                 if (detailNameCell != null) {
                     patrolPoint.setDetailName(getCellStringValue(detailNameCell));
                 }
                 
                 // 用途
                 Cell purposeCell = row.getCell(5);
                 if (purposeCell != null) {
                     patrolPoint.setPurpose(getCellStringValue(purposeCell));
                 }

                 // 安全员姓名
                 Cell guardNameCell = row.getCell(6);
                 if (guardNameCell != null) {
                     patrolPoint.setGuardName(getCellStringValue(guardNameCell));
                 }

                 // 安全员电话
                 Cell guardPhoneCell = row.getCell(7);
                 if (guardPhoneCell != null) {
                     patrolPoint.setGuardPhone(getCellStringValue(guardPhoneCell));
                 }
                 
                 // 点位编码（必填）
                 Cell pointCodeCell = row.getCell(8);
                 if (pointCodeCell != null) {
                     patrolPoint.setPointCode(getCellStringValue(pointCodeCell));
                 }
                 
                 patrolPointList.add(patrolPoint);
             }
         } finally {
             if (workbook != null) {
                 workbook.close();
             }
         }
         
         return patrolPointList;
     }
    
    /**
     * 获取单元格字符串值
     */
    private String getCellStringValue(Cell cell)
    {
        if (cell == null)
        {
            return "";
        }
        
        switch (cell.getCellType())
        {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell))
                {
                    return cell.getDateCellValue().toString();
                }
                else
                {
                    // 数字类型转换为字符串，去掉小数点后的0
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue == (long) numericValue)
                    {
                        return String.valueOf((long) numericValue);
                    }
                    else
                    {
                        return String.valueOf(numericValue);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }
    
    /**
     * 校验点位编码唯一性
     */
    @ApiOperation("校验点位编码唯一性")
    @GetMapping("/checkPointCodeUnique")
    public AjaxResult checkPointCodeUnique(String pointUniqueCode)
    {
        if (StringUtils.isEmpty(pointUniqueCode))
        {
            return AjaxResult.error("点位唯一编码不能为空");
        }
        boolean result = patrolPointService.checkPointCodeUnique(pointUniqueCode, null);
        return AjaxResult.success(result);
    }
    
    /**
     * 根据二维码code查询点位信息
     */
    @ApiOperation("根据二维码code查询点位信息")
    @GetMapping("/getByQrCode")
    public AjaxResult getByQrCode(String qrCode)
    {
        if (StringUtils.isEmpty(qrCode))
        {
            return AjaxResult.error("二维码code不能为空");
        }
        PatrolPoint patrolPoint = patrolPointService.selectPatrolPointByQrCode(qrCode);
        return AjaxResult.success(patrolPoint);
    }
    
    /**
     * 导入点位数据
     */
    @ApiOperation("导入点位数据")
    @RequiresPermissions("campus:point:import")
    @Log(title = "巡查点位信息", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public AjaxResult importData(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception
    {
        // 校验文件不能为空
        if (file == null || file.isEmpty())
        {
            return AjaxResult.error("上传文件不能为空");
        }
        
        // 校验文件格式
        String fileName = file.getOriginalFilename();
        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls")))
        {
            return AjaxResult.error("请上传Excel格式文件(.xlsx或.xls)");
        }
        
        // 使用自定义Excel解析方法
        List<PatrolPoint> patrolPointList = parsePatrolPointExcel(file.getInputStream());
        String operName = getLoginName();
        String message = patrolPointService.importPatrolPoint(patrolPointList, updateSupport, operName);
        return AjaxResult.success(message);
    }
    
    /**
     * 下载点位导入模板
     */
    @ApiOperation("下载点位导入模板")
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) throws Exception
    {
        // 直接下载resources目录下的模板文件
        String fileName = "点位管理-导入模板.xlsx";
        
        try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName)) {
            if (inputStream == null) {
                throw new Exception("模板文件不存在: " + fileName);
            }
            
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, fileName);
            
            // 直接从输入流复制到输出流
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                response.getOutputStream().write(buffer, 0, bytesRead);
            }
            response.getOutputStream().flush();
        }
    }
    
    /**
     * 获取点位二维码base64
     */
    @ApiOperation("获取点位二维码base64")
    @GetMapping("/qrCodeBase64/{pointId}")
    public AjaxResult getQrCodeBase64(@PathVariable Long pointId)
    {
        if (pointId == null)
        {
            return AjaxResult.error("点位ID不能为空");
        }
        String base64 = patrolPointService.getQrCodeBase64(pointId);
        if (StringUtils.isEmpty(base64))
        {
            return AjaxResult.error("获取二维码失败");
        }
        return AjaxResult.success("data:image/png;base64," + base64);
    }
    
    /**
     * 批量下载二维码
     */
    @ApiOperation("批量下载二维码")
    @RequiresPermissions("campus:point:export")
    @Log(title = "巡查点位二维码", businessType = BusinessType.EXPORT)
    @PostMapping("/batchDownloadQrCode")
    public void batchDownloadQrCode(PatrolPoint patrolPoint, HttpServletResponse response)
    {
        if (patrolPoint == null || patrolPoint.getDeptId() == null) {
            return;
        }
        patrolPointService.batchDownloadQrCode(patrolPoint, response);
    }
}
